//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "namedmutex.h"
#include "cthread.h"
#include "pseudo.h"
#include "pcentral.h"
#include "helper.h"
#include <aura.h>

#undef Lock
#undef Unlock

CNamedMutex::~CNamedMutex()
{
    if (NULL != m_hMutex) {
        AuraMutex_Destroy(m_hMutex);
        m_hMutex = NULL;
    }
    if (NULL != m_pName) {
        WStringBuf::Free(m_pName);
        m_pName = NULL;
    }
}

ECode CNamedMutex::Initialize(
        /* [in] */ WString name)
{
    Int32 length = name.GetLength(AURA_MAX_PATH) + 1;
    ECode ec = NOERROR;

    m_pName = WStringBuf::Alloc(length);
    if (NULL == m_pName) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    m_pName->Copy(name);

    ec = AuraMutex_Create((Aura_PWChar)(const wchar_t *)name,
                                AURA_TRUE,
                                &m_hMutex);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    return NOERROR;

ErrorExit:
    if (NULL != m_pName) {
        WStringBuf::Free(m_pName);
        m_pName = NULL;
    }
    return ec;
}

PInterface CNamedMutex::Probe(
    /* [in]  */ REIID riid)
{
    if (riid == EIID_IInterface) {
        return (PInterface)(IMutex *)this;
    }
    else if (riid == EIID_IMutex) {
        return (IMutex *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CMutex;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface)&EIID_IMutex;
    }

    return NULL;
}

UInt32 CNamedMutex::AddRef()
{
    Int32 nRef = m_cRef.Increment();

    return (UInt32)nRef;
}

UInt32 CNamedMutex::Release()
{
    Int32 nRef = m_cRef.Decrement();

    if (0 >= nRef) {
        CNamedMutexFactory factory(*m_pName);
        NamedObject::S_DestroyObject(&factory, m_oid);
        delete this;
    }
    return (UInt32)nRef;
}

ECode CNamedMutex::Aggregate(
    /* [in]  */ AggrType type,
    /* [in]  */ PInterface pObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CNamedMutex::GetDomain(
    /* [out] */ PInterface * ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CNamedMutex::Lock(
    /* [out] */ WaitResult * pResult)
{
    return TryLock(INFINITE, pResult);
}

ECode CNamedMutex::TryLock(
    /* [in]  */ Millisecond32 msTimeout,
    /* [out] */ WaitResult * pResult)
{
    ECode ec = NOERROR;

    if (NULL == pResult) {
        return E_INVALID_ARGUMENT;
    }

    THREAD_START_SLEEP_NAMED()
    {
        ec = AuraMutex_Lock(m_hMutex,
                        msTimeout,
                       (Aura_WaitResult *)pResult);
    }
    THREAD_END_SLEEP_NAMED;

    return ec;
}

ECode CNamedMutex::Unlock()
{
    return (ECode)AuraMutex_Unlock(m_hMutex);
}

ECode CNamedMutexFactory::CreateNamedObject(
            /* [out] */ NamedObject ** ppNamedObj,
            /* [out] */ Boolean * pbAlreadyExisted)
{
    CNamedMutex * pMutex = NULL;
    ECode ec = NOERROR;
    oid_t oid = 0;

    assert(NULL != ppNamedObj);
    assert(NULL != pbAlreadyExisted);

    ec = CPseudoCentral::CreateNamedMutex(m_name, pbAlreadyExisted, &oid);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    pMutex = new CNamedMutex(oid);
    if (NULL == pMutex) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    ec = pMutex->Initialize(m_name);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    pMutex->AddRef();
    *ppNamedObj = pMutex;

    return ec;

ErrorExit:
    if (NULL != pMutex) {
        delete pMutex;
    }
    if (oid > 0) {
        CPseudoCentral::ReleaseNamedObject(oid);
    }
    return ec;
}

ECode CNamedMutexFactory::ResolveNamedObject(
            /* [in]  */ oid_t oid,
            /* [out] */ NamedObject ** ppNamedObj)
{
    CNamedMutex * pMutex = NULL;
    ECode ec = NOERROR;

    assert(NULL != ppNamedObj);

    pMutex = new CNamedMutex(oid);
    if (NULL == pMutex) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    ec = pMutex->Initialize(m_name);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = CPseudoCentral::AddRefNamedObject(oid);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    pMutex->AddRef();
    *ppNamedObj = pMutex;

    return ec;

ErrorExit:
    if (NULL != pMutex) {
        delete pMutex;
    }
    return ec;
}

ECode CNamedMutexFactory::DestroyNamedObject(
            /* [in]  */ oid_t oid)
{
    return CPseudoCentral::ReleaseNamedObject(oid);
}

